﻿namespace Ymatou.UserAuth.Agent.Sso
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;

    /// <summary>
    /// EncryptorHelp
    /// </summary>
    public class EncryptorHelp
    {
        /// <summary>
        ///  导出公钥，私钥
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="privateKey"></param>
        public static void ImportDSAKey(out string publicKey, out string privateKey)
        {
            var dsa = new DSACryptoServiceProvider();
            publicKey = dsa.ToXmlString(false);
            privateKey = dsa.ToXmlString(true);
        }
        /// <summary>
        /// DSA 签名
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="DataToSign"></param>
        /// <param name="en"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static string DSASignData(string privateKey, string DataToSign, Encoding en, out bool error)
        {
            error = false;
            try
            {
                var DSA = new DSACryptoServiceProvider();
                DSA.FromXmlString(privateKey);
                var by = DSA.SignData(en.GetBytes(DataToSign));
                return Convert.ToBase64String(by);
            }
            catch (CryptographicException ex)
            {
                error = true;
                return ex.ToString();
            }
        }
        /// <summary>
        /// DSA 签名
        /// </summary>
        /// <param name="DataToSign"></param>
        /// <param name="DSAKeyInfo"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static byte[] DSASignData(byte[] DataToSign, DSAParameters DSAKeyInfo, out string error)
        {
            try
            {
                error = string.Empty;
                //Create a new instance of DSACryptoServiceProvider.
                DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();

                //Import the key information.   
                DSA.ImportParameters(DSAKeyInfo);

                //Compute hash value, sign the hash, and return the signed hash.
                return DSA.SignData(DataToSign);
            }
            catch (CryptographicException e)
            {
                error = e.ToString();
                return null;
            }

        }
        /// <summary>
        /// DSA 签名验证
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="signData">已签名的数据</param>
        /// <param name="verifyData">要验证的数据</param>
        /// <param name="error">是否出错</param>
        /// <returns></returns>
        public static bool DSAVerifyData(string publicKey, string signData, byte[] verifyData, out string error)
        {
            error = string.Empty;
            try
            {
                var dsa = new DSACryptoServiceProvider();
                dsa.FromXmlString(publicKey);
                var signBy = Convert.FromBase64String(signData);

                return dsa.VerifyData(signBy, verifyData); ;
            }
            catch (CryptographicException ex)
            {
                error = ex.ToString();
                return false;
            }
        }
        /// <summary>
        /// DSA 签名验证
        /// </summary>
        /// <param name="Data"></param>
        /// <param name="SignedData"></param>
        /// <param name="DSAKeyInfo"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static bool DSAVerifyData(byte[] Data, byte[] SignedData, DSAParameters DSAKeyInfo, out string error)
        {
            try
            {
                error = string.Empty;
                //Create a new instance of DSACryptoServiceProvider.
                var DSA = new DSACryptoServiceProvider();

                //Import the key information. 
                DSA.ImportParameters(DSAKeyInfo);

                //Verify the signature and return the result.	
                return DSA.VerifyData(Data, SignedData);

            }
            catch (CryptographicException e)
            {
                error = e.ToString();
                return false;
            }
        }
        /// <summary>
        /// RSA 分组加密（用于大于128位的数据）
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="originalData"></param>
        /// <param name="en"></param>
        /// <param name="error">是否出错</param>
        /// <returns></returns>
        public static string RSAGroupingEncryptor(string publicKey, string originalData, Encoding en, out bool error)
        {
            error = false;
            try
            {
                byte[] encryptDada = en.GetBytes(originalData);
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(publicKey);
                //获取RSA最大加密的长度
                Int32 KeySize = rsa.KeySize / 8;
                Int32 BlockSize = KeySize - 11;
                if (encryptDada.Length > BlockSize)
                {
                    //分配加密次数
                    Int32 EncryptIndex = 0;
                    if (encryptDada.Length % BlockSize != 0)//不能整除
                    {
                        EncryptIndex = encryptDada.Length / BlockSize + 1;
                    }
                    else
                    {
                        EncryptIndex = encryptDada.Length / BlockSize;
                    }
                    //分配存储已加密的byte数组，请注意下这里分配的大小
                    //每次只能加密117长度的数据，但是每次加密117长度的数据要生成128长度的密文。
                    Byte[] EncryptByte = new Byte[EncryptIndex * KeySize];
                    for (Int32 i = 0; i < EncryptIndex; i++)
                    {
                        Byte[] Block = new Byte[BlockSize];
                        if (i == (EncryptIndex - 1))
                        {
                            //最后一次加密
                            Array.Copy(encryptDada, i * BlockSize, Block, 0, encryptDada.Length % BlockSize);
                        }
                        else
                        {
                            Array.Copy(encryptDada, i * BlockSize, Block, 0, BlockSize);
                        }
                        Byte[] Block1 = rsa.Encrypt(Block, false);
                        //将加密过的Byte数组保存到EncryptByte中
                        Array.Copy(Block1, 0, EncryptByte, i * KeySize, KeySize);
                    }
                    return Convert.ToBase64String(EncryptByte);
                }
                else
                {
                    byte[] b = rsa.Encrypt(encryptDada, false);
                    return Convert.ToBase64String(b);
                }
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.Message;
            }
        }
        /// <summary>
        /// RSA 分组解密（用于大于128位的数据）
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="encryptDada"></param>
        /// <param name="en"></param>
        /// <param name="error">是否出错</param>
        /// <returns></returns>
        public static string RSAGroupingDecryptor(string privateKey, string encryptDada, Encoding en, out bool error)
        {
            error = false;

            try
            {
                byte[] encryptDadaArr = Convert.FromBase64String(encryptDada);//en.GetBytes(encryptDada);
                Byte[] Block1;
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(privateKey);
                Int32 KeySize = rsa.KeySize / 8;
                Int32 BlockSize = KeySize - 11;
                if (encryptDadaArr.Length == KeySize)
                {
                    return en.GetString(rsa.Decrypt(encryptDadaArr, false));
                }
                else
                {
                    //这个变量用来记录所有解密后的Byte数组的长度
                    Int32 Len = 0;
                    //保存每次解密后的Byte数组
                    List<Byte[]> list = new List<Byte[]>();
                    //计算解密需要的次数
                    Int32 EncryptIndex = encryptDadaArr.Length / KeySize;

                    for (Int32 i = 0; i < EncryptIndex; i++)
                    {
                        Byte[] Block = new Byte[KeySize];
                        Array.Copy(encryptDadaArr, i * KeySize, Block, 0, KeySize);
                        Block1 = rsa.Decrypt(Block, false);
                        Len += Block1.Length;
                        list.Add(Block1);
                    }
                    Byte[] EncryptByte = new Byte[Len];
                    for (Int32 i = 0; i < list.Count; i++)
                    {
                        Array.Copy(list[i], 0, EncryptByte, i * BlockSize, BlockSize);
                    }
                    return en.GetString(EncryptByte);
                }
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.Message;
            }
        }
        /// <summary>
        /// RSA导出公钥，私钥
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="privateKey"></param>
        public static void ImportRSAKey(out string publicKey, out string privateKey)
        {
            var cp = new CspParameters();
            cp.KeyContainerName = "ymatouKeyContainer";
            var context = new RSACryptoServiceProvider(cp);
            publicKey = context.ToXmlString(false);

            privateKey = context.ToXmlString(true);
        }
        /// <summary>
        /// 加密 。如果异常error 返回true，并且返回异常消息。
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="str"></param>
        /// <param name="error">是否错误</param>
        /// <returns></returns>
        public static string RSAEncryptor(string publicKey, string str, Encoding coding, out bool error)
        {
            try
            {
                error = false;
                var rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(publicKey);
                return Convert.ToBase64String(rsa.Encrypt(coding.GetBytes(str), false));
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.ToString();
            }
        }
        /// <summary>
        ///  加密 。如果异常error 返回true，并且返回错误消息。
        /// </summary>
        /// <param name="publicKey"></param>
        /// <param name="str"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static string RSAEncryptor(string publicKey, byte[] str, out bool error)
        {
            try
            {
                error = false;
                var rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(publicKey);
                return Convert.ToBase64String(rsa.Encrypt(str, false));
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.ToString();
            }
        }
        /// <summary>
        /// 解密。如果异常error 返回true，并且返回 null。
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="str"></param>
        /// <param name="en"></param>
        /// <param name="error">是否错误</param>
        /// <returns></returns>
        public static string RSADecryptor(string privateKey, byte[] str, Encoding en, out bool error)
        {
            try
            {
                error = false;
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(privateKey);
                return en.GetString(rsa.Decrypt(str, false));
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.ToString();
            }
        }
        /// <summary>
        ///  解密。如果异常error 返回true，并且返回错误消息。 
        /// </summary>
        /// <param name="privateKey"></param>
        /// <param name="str"></param>
        /// <param name="en"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static string RSADecryptor(string privateKey, string str, Encoding en, out bool error)
        {
            try
            {
                error = false;
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(privateKey);
                return en.GetString(rsa.Decrypt(Convert.FromBase64String(str), false));
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.ToString();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="KeyPar"></param>
        /// <param name="Str"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static string RSAEncryptor(RSAParameters KeyPar, byte[] Str, out bool error)
        {
            try
            {
                error = false;
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.ImportParameters(KeyPar);
                return Convert.ToBase64String(rsa.Encrypt(Str, false));
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.ToString();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="KeyPar"></param>
        /// <param name="Str"></param>
        /// <param name="en"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public static string RSADecryptor(RSAParameters KeyPar, byte[] Str, Encoding en, out bool error)
        {
            try
            {
                error = false;
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.ImportParameters(KeyPar);
                return en.GetString(rsa.Decrypt(Str, false));
            }
            catch (CryptographicException e)
            {
                error = true;
                return e.ToString();
            }
        }
    }
}
